package reflect

import (
	"errors"
	"reflect"
	"strings"
)

//计算变量大小。由于slice和map数据动态变化，因此计算reflect.Value大小。
//其他类型在声明的时刻大小已固定，计算reflect.Type即可
func GetDataSize(i interface{}) int {
	value := reflect.ValueOf(i)
	switch value.Kind() {
	case reflect.Ptr:
		value = value.Elem()
		return GetDataSize(value.Interface()) //value.Interface()带有类型信息
	case reflect.Slice:
		if s := GetTypeSize(value.Type().Elem()); s > 0 {
			return s * value.Len()
		}
		return 0
	case reflect.Map:
		if value.Len() == 0 {
			return 0
		}
		sum := 0
		keys := value.MapKeys()
		for i := 0; i < len(keys); i++ {
			key := keys[i]
			v := value.MapIndex(key)
			sum += GetDataSize(v.Interface())
		}
		return sum
	case reflect.String:
		return value.Len()

	default:
		return GetTypeSize(value.Type())
	}
}

//计算reflect.Type大小
func GetTypeSize(t reflect.Type) int {
	switch t.Kind() {
	case reflect.Bool,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
		return int(t.Size())

	case reflect.Array:
		if s := GetTypeSize(t.Elem()); s > 0 {
			return s * t.Len()
		}
		return 0

	case reflect.Struct:
		sum := 0
		for i := 0; i < t.NumField(); i++ {
			sum += GetTypeSize(t.Field(i).Type)
		}
		return sum
	}
	return 0
}

//map转为struct类型
func FromMap(m map[string]interface{}, i interface{}) interface{} {
	t := reflect.TypeOf(i)
	if t.Kind() != reflect.Ptr {
		return errors.New("i is not a pointer")
	}
	if t.Elem().Kind() == reflect.Ptr {
		return errors.New("i is a pointer to pointer")
	}

	//对象赋值
	ptr := reflect.New(t.Elem())
	for k, v := range m {
		k = strings.ToUpper(k)
		fieldValue := ptr.Elem().FieldByName(k)

		//fmt.Printf("set field=%v, value=%v\n", k, v)
		if !fieldValue.IsValid() {
			//struct不包含此字段，跳过
			continue
		}
		//go方法为值传递，因此传递指针
		setValue(v, &fieldValue)
		//重新设置value
		ptr.Elem().FieldByName(k).Set(fieldValue)
	}

	return ptr.Interface()
}

//属性赋值  基本类型 array slice map struct chan
func setValue(i interface{}, fieldValue *reflect.Value) {
	switch data := i.(type) {
	case int, int8, int16, int32, int64:
		fieldValue.SetInt(reflect.ValueOf(data).Int())
	case *int, *int8, *int16, *int32, *int64:
		fieldValue.SetInt(reflect.ValueOf(data).Elem().Int())
	case uint, uint8, uint16, uint32, uint64:
		fieldValue.SetUint(reflect.ValueOf(data).Uint())
	case *uint, *uint8, *uint16, *uint32, *uint64:
		fieldValue.SetUint(reflect.ValueOf(data).Elem().Uint())
	case bool:
		fieldValue.SetBool(data)
	case *bool:
		fieldValue.SetBool(*data)
	case float32, float64:
		fieldValue.SetFloat(reflect.ValueOf(data).Float())
	case complex64, complex128:
		fieldValue.SetComplex(reflect.ValueOf(data).Complex())
	case *float32, *float64:
		fieldValue.SetFloat(reflect.ValueOf(data).Elem().Float())
	case *complex64, *complex128:
		fieldValue.SetComplex(reflect.ValueOf(data).Elem().Complex())
	case string:
		fieldValue.SetString(data)
	default:
		//复合类型
		dataValue := reflect.ValueOf(data)
		switch dataValue.Kind() {
		case reflect.Array:
			if fieldValue.Type().Kind() != reflect.Array {
				return
			}
			for i := 0; i < dataValue.Len(); i++ {
				//索引赋值
				v1 := fieldValue.Index(i)
				setValue(dataValue.Index(i).Interface(), &v1)
			}

		case reflect.Slice:
			if fieldValue.Type().Kind() != reflect.Slice {
				return
			}
			if fieldValue.IsNil() {
				//创建切片
				*fieldValue = reflect.MakeSlice(fieldValue.Type(), dataValue.Len(), dataValue.Len())
			}
			for i := 0; i < dataValue.Len(); i++ {
				//索引赋值
				v1 := fieldValue.Index(i)
				setValue(dataValue.Index(i).Interface(), &v1)
			}

		case reflect.Map:
			//map元素映射为map或struct
			kind := fieldValue.Type().Kind()
			if kind != reflect.Map && kind != reflect.Struct {
				//目标值非map或struct，返回
				return
			}
			if kind == reflect.Map {
				//map赋值为map
				keys := dataValue.MapKeys()
				if len(keys) == 0 || keys[0].Kind() != reflect.String {
					return
				}

				if fieldValue.IsNil() {
					//创建map
					*fieldValue = reflect.MakeMap(fieldValue.Type())
				}
				m1 := fieldValue.Interface().(map[string]interface{})
				//按key、value赋值
				for i := 0; i < len(keys); i++ {
					key := keys[i]
					v1 := dataValue.MapIndex(key)
					m1[key.String()] = v1.Interface()
				}
			}
			if kind == reflect.Struct {
				//map赋值为struct
				keys := dataValue.MapKeys()
				if len(keys) == 0 || keys[0].Kind() != reflect.String {
					return
				}
				//按key、value赋值
				for i := 0; i < len(keys); i++ {
					key := keys[i]
					v := dataValue.MapIndex(key)
					v1 := fieldValue.FieldByName(key.String())
					setValue(v.Interface(), &v1)
				}
			}
		case reflect.Struct:
			//struct元素映射为map或struct
			kind := fieldValue.Type().Kind()
			if kind != reflect.Struct {
				//目标值非struct，返回
				return
			}

			for i := 0; i < dataValue.NumField(); i++ {
				f := dataValue.Field(i)
				v1 := fieldValue.Field(i)
				setValue(f.Interface(), &v1)
			}

		case reflect.Chan:
			//channel元素赋值
			kind := fieldValue.Type().Kind()
			if kind != reflect.Chan {
				return
			}
			if fieldValue.IsNil() {
				*fieldValue = reflect.MakeChan(fieldValue.Type(), 0)
			}
		}
	}
}

//struct转为map  struct字段转为map，基本类型/array/slice/map原样赋值即可
func ToMap(i interface{}) (map[string]interface{}, error) {
	value := reflect.ValueOf(i)
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	if value.Kind() != reflect.Struct {
		return nil, errors.New("i is not a struct")
	}

	m := map[string]interface{}{}
	for i := 0; i < value.NumField(); i++ {
		v := value.Field(i)
		if v.Kind() == reflect.Ptr {
			v = v.Elem()
		}
		f := value.Type().Field(i) //StructField
		name := f.Name

		switch v.Kind() {
		case reflect.Struct:
			m1, err := ToMap(v.Interface())
			if err != nil {
				continue
			}
			m[name] = m1
		default:
			m[name] = v.Interface()
		}
	}

	return m, nil
}
